package controllers;

import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.codehaus.jackson.node.ObjectNode;
import org.joda.time.DateTime;

import com.avaje.ebean.Ebean;
import com.avaje.ebean.SqlRow;

import common.CourseDetailsForMobile;
import common.ExtendedComment;
import common.ExtendedCourse;
import common.MobileUtils;
import common.UnAuthorizedDeviceException;

import models.*;
import play.data.Form;
import play.db.ebean.Model;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;
import recommend.RecommendationCalculator;
import search.SearchableIndexer;
import play.mvc.Http.Session;
import views.html.*;
import views.html.defaultpages.error;

public class Course extends Controller {
	
	public static Result coursecomments(String Id) {

		String s="SELECT ecm.comment_id,FROM_UNIXTIME(ecm.comment_date) AS comment_date,eu.name,eu.surname,ecm.comment, "+
		"(SELECT COUNT(vote_id) FROM edu_commentvotes WHERE vote=1 AND comment_id=ecm.comment_id) AS agree, "+
		"(SELECT COUNT(vote_id) FROM edu_commentvotes WHERE vote=0 AND comment_id=ecm.comment_id) AS disagree "+
		"FROM edu_comments ecm "+
		"JOIN edu_courses ec ON ecm.course_id=ec.course_id "+
		"JOIN edu_users eu ON ecm.user_id=eu.user_id "+
		"WHERE ecm.course_id="+Id+" "+
		"ORDER BY ecm.course_id";
		return ok(Json.toJson(Ebean.createSqlQuery(s).findList().toArray()));
	
	}
	
	public static Result courseDetail(String Id){ 	
		
		
		edu_courses ec = edu_courses.findById(Integer.parseInt(Id));
		edu_instructors ei = edu_instructors.findById(ec.instructor_id);
		edu_institutions ein = edu_institutions.findById(ec.institution_id);
		List<edu_comments> eco = edu_comments.listCourseComments(Integer.parseInt(Id));
		
		List<ExtendedComment> exCommends = new ArrayList<ExtendedComment>();
		if(eco.size() > 0){
			edu_users user = edu_users.findById(eco.get(0).user_id);
			for (edu_comments ec2 : eco) {
				exCommends.add(new ExtendedComment(user.name, ec2));
			}
		}		
		
		
		List<edu_tags> et = edu_tags.findByCourseID(Id);
		edu_coursesstudents ecs = new edu_coursesstudents(); 
		if (session().containsKey("user_id"))
		{
			ecs = edu_coursesstudents.findByCourseNStudentId(Integer.parseInt(Id), Integer.parseInt(session().get("user_id")));
		}
		else
		{
			ecs = null;
		}
    	return ok(views.html.coursedetails.render(Id, ec, ei, ein, eco, et, ecs));
    }
	
	public static Result getCourseDetails(String Id,String userDeviceId) throws UnAuthorizedDeviceException{
		if(MobileUtils.IsAuthenticatedDevice(userDeviceId)){
			ExtendedCourse ec = new ExtendedCourse(edu_courses.findById(Integer.parseInt(Id)));
			List<edu_comments> eco = edu_comments.listCourseComments(Integer.parseInt(Id));
			List<ExtendedComment> exCommends = new ArrayList<ExtendedComment>();
			if(eco.size() > 0){
				for (edu_comments ec2 : eco) {
					edu_users user = edu_users.findById(ec2.user_id);
					exCommends.add(new ExtendedComment(user.name, ec2));
				}
			}
			ec.instructor_name = edu_instructors.findById(ec.instructor_id).name;
			ec.instution_name = edu_institutions.findById(ec.institution_id).name;
			List<edu_tags> et = edu_tags.findByCourseID(Id);
			return ok(Json.toJson(new CourseDetailsForMobile(ec,exCommends, et)));
		}
		throw new UnAuthorizedDeviceException();
	}
	
	public static Result dropCourse(String Id){			
		edu_coursesstudents.dropCourse(Integer.parseInt(Id), Integer.parseInt(session().get("user_id")));
		
		return redirect(routes.Course.myCourseList());	
	}
	
	public static Result enrollCourse(String Id){
		if (!session().containsKey("user_id")) {
			return redirect(routes.User.register());
		}
		else {		
			long unixTime = System.currentTimeMillis() / 1000L;
			edu_coursesstudents new_ecs = new edu_coursesstudents();
			new_ecs.course_id = Integer.parseInt(Id);
			new_ecs.user_id = Integer.parseInt(session().get("user_id"));	
			new_ecs.registration_date = (int)unixTime;
			new_ecs.save();
			
			return redirect(routes.Course.myCourseList());
		}
	}	

	public static Result courseLectures(String Id){		
		edu_courses ec = edu_courses.findById(Integer.parseInt(Id));
		edu_instructors ei = edu_instructors.findById(ec.instructor_id);
		edu_institutions ein = edu_institutions.findById(ec.institution_id);
		List<edu_comments> eco = edu_comments.listCourseComments(Integer.parseInt(Id));
		List<edu_courses> el = edu_courses.listLectures(Integer.parseInt(Id));
		//List<edu_tags> et = edu_tags.findByCourseID(Id);
    	return ok(views.html.courselectures.render(Id, ec, ei, ein, eco, el));
    }	
	
	
	
	public static Result addCourse(){
    	return ok(addnewcourse.render());
    }	
	public static Result myCourseList(){
    	return ok(courselist.render());
    }
	public static Result newInstitution(){
		return ok(newinstutition.render());
    }
	public static Result newInstructor(){
		return ok(newinstructor.render());
    }

	public static Result showInstructor(String Id){
		edu_instructors ei = edu_instructors.findById(Integer.parseInt(Id));
		List<edu_courses> ec = edu_courses.find.where().eq("instructor_id", Integer.parseInt(Id)).eq("parent_id",0).findList();
		return ok(instructor.render(ei, ec));
    }
	
	public static Result showInstitution(String Id){
		edu_institutions ei = edu_institutions.findById(Integer.parseInt(Id));
		List<edu_courses> ec = edu_courses.find.where().eq("institution_id", Integer.parseInt(Id)).eq("parent_id",0).findList();
		return ok(institution.render(ei, ec));
    }	
	
	public static void addNewInstutition(){
		
    }
	
	public static Result addCourseToEdunera(){
		
		//edu_users eu=Form.form(edu_users.class).bindFromRequest().get();
		//eu.save();
			    
		edu_courses ec = new edu_courses();		
		edu_tags et = new edu_tags();
		
		String courseName = Form.form().bindFromRequest().get("name");
		String courseCode = Form.form().bindFromRequest().get("code");
		String courseDescription = Form.form().bindFromRequest().get("description");
		String courseShortDescription = Form.form().bindFromRequest().get("shortDescription");
		String courseStartDate = Form.form().bindFromRequest().get("startDate");
		String courseEndDate = Form.form().bindFromRequest().get("endDate");
		String courseTags = Form.form().bindFromRequest().get("tags");
		
	     
	    /* 
	    SimpleDateFormat dateFormat = new SimpleDateFormat("dd-mm-yyyy"); 
	    Date startDate = dateFormat.parse(courseStartDate); 		
	    Date endDate = dateFormat.parse(courseEndDate);
		*/
		
		ec.name = courseName;
		ec.code = courseCode;
		ec.is_active = 1;
		ec.parent_id = 0;
		ec.institution_id = 0;
		ec.instructor_id = 0;
		ec.start_date = 0;
		ec.end_date = 0;
		ec.short_description = courseShortDescription;
		ec.description = courseDescription;
		ec.created_by = 0;
		ec.creation_date = System.currentTimeMillis()/1000;
		ec.save();
				
		int new_course_id = ec.course_id;
		
		String[] tagList = courseTags.split(",");
		for (int i = 0; i< tagList.length; i++)
		{
			String tag = tagList[i].trim();
			ec.addTagToCourse(new_course_id, tag);			
		}
		return redirect(routes.Course.courseDetail(Integer.toString(ec.course_id)));
	}
	
	public static Result findCourseUrl(String Id){
		edu_courses c = new edu_courses();
		c = c.findById(Integer.parseInt(Id));
		return ok(Json.toJson(c.url));
	}
	
	public static Result mobileCourseList(String userDeviceId){
        Object[] eu=MobileUtils.findUserDevice(userDeviceId);
        return ok(Json.toJson(eu));
	}
	
	public static Result addRate(String Id, String rate){
		
		 System.out.println("geldim"); 
         edu_courserates cr=new edu_courserates();
         cr.course_id=Integer.parseInt(Id);
         cr.course_rate= Float.parseFloat(rate);
         cr.save();
         System.out.println("saved killer");
        //return redirect(routes.Course.courseDetail(Id));
		return ok("it works!!");
	}
   public static Result showRatemean(String Id){
		 
	   String s="SELECT AVG(IFNULL(edu_courserates.course_rate,0)) as course_rate "+
				"FROM edu_courserates " +
				"Where edu_courserates.course_id='"+Id+"'";
	   
		return ok(Json.toJson(Ebean.createSqlQuery(s).findList().toArray()));
	}
   public static Result addNewTag(String course_id, String tag_name){
		
	   try{
		   System.out.println("geldim"); 
	       edu_tags tg=new edu_tags();
	       edu_tags ntag=new edu_tags();
	       edu_tagscourses ct=new edu_tagscourses();
	       tg=edu_tags.findByName(tag_name);
	       
	       if(tg==null || tg.tag_id<1){
	    	   try{
	    		   ntag.tag=tag_name;
	        	   ntag.save();
	        	   tg=edu_tags.findByName(tag_name);   
	    	   }catch(Exception ex){
	    		   ex.printStackTrace();
	    	   }
	    	   
	       }
	       
	       String sq="SELECT * FROM edu_tagscourses WHERE edu_tagscourses.course_id='"+Integer.parseInt(course_id)+"' AND edu_tagscourses.tag_id='"+tg.tag_id+"'";
	       Object[] ccc= Ebean.createSqlQuery(sq).findList().toArray();
	       if(ccc.length==0)
	       {
	       
	       if(tg.tag!=null)
	       {
	    	   System.out.println(tg.tag_id);
	    	   ct.tag_id=tg.tag_id;
			   ct.course_id=Integer.parseInt(course_id);
			   ct.added_by_user_id=Integer.parseInt(session().get("user_id"));
			   ct.vote=3;
			   ct.save();
	    	   
	    	   
	       } }
	   }catch(Exception ex){
		   ex.printStackTrace();
	   }
		return ok("It Works!!");
	}
	
   
   public static Result getRecommendedCourses(String courseId){
		Map<Integer,Integer> clusterMap = 
				RecommendationCalculator.clusterInfo.getSequenceAndClusterIdxMap();
		if(clusterMap.containsKey(Integer.parseInt(courseId))){
			int clusterIndex = clusterMap.get(Integer.parseInt(courseId));
			return ok(Json.toJson(RecommendationCalculator.clusterInfo.getClusterIdxAndRelatedSeqIds().get(clusterIndex)));
		}
		return ok(Json.toJson(new ArrayList<Integer>()));
	}
   
   private static int calculateDiff(double[] a,double[] b){
	   int len = a.length;
	   int total = 0;
	   for (int i = 0; i < len; i++) {
		   total+=Math.pow(a[i] - b[i],2);
	   }
	   return total;
   }
   
   private static Object[] fetchRecommendedCoursesForUser(String userId){
	   String docCountQuery = "select count(c.course_id) docCount from edu_courses c "+ 
				"order by c.course_id;";
	   	int docCount = Ebean.createSqlQuery(docCountQuery).findUnique().getInteger("docCount");
	   	
	   String s="SELECT edu_coursesstudents.course_id " +
				"FROM edu_coursesstudents " +
				"LEFT Join edu_courses " +
					"on edu_coursesstudents.course_id=edu_courses.course_id " +
				"LEFT Join edu_instructors " +
					"on edu_courses.instructor_id = edu_instructors.id " +
				"LEFT Join edu_institutions " +
					"on  edu_courses.institution_id = edu_institutions.id " +
				"LEFT Join edu_users " +
					"on edu_coursesstudents.user_id=edu_users.user_id " +
				"LEFT Join edu_courserates " +
					"on edu_courserates.course_id=edu_users.user_id " +
				"Where edu_users.user_id='"+userId+"'";
	   	Set<Integer> courses = new HashSet<Integer>();
	   	List<SqlRow> rows = Ebean.createSqlQuery(s).findList();
	   	
	   	double[] userData = new double[docCount];
	   	for (SqlRow row : rows) {
	   		userData[row.getInteger("course_id")] =1;
	   		courses.add(row.getInteger("course_id"));
		}
	   	
	   	Set<Integer> recommendedCourses = new HashSet<Integer>();
	   	SortedMap<Integer, Integer> diffMap = new TreeMap<Integer, Integer>();
	   	double[][] data = RecommendationCalculator.getData();
	   	for (int i = 0; i < data.length; i++) {
	   		diffMap.put(calculateDiff(data[i],userData),i);
		}
	   	
	   	int count = 0;
	   	for (Integer diff : diffMap.keySet()) {
			if(diff>0 && count < 5){
				for (int i = 0; i < docCount; i++) {
					if(data[diffMap.get(diff)][i] == 1){
						recommendedCourses.add(i);
					}
				}
				count++;
			}
		}
	   	for (Integer it : courses) {
			System.out.println(it+" ");
		}
	   	
	   	recommendedCourses.removeAll(courses);
	   	StringBuilder sb = new StringBuilder();
	   	for (Integer c : recommendedCourses) {
	   		sb.append(c+", ");
	   		//System.out.println(c);
		}
	   	if(sb.length() > 2){
	   		sb.delete(sb.length()-2,sb.length());
	   	}
	   	if(!sb.toString().trim().equals("")){
		   	String rs="SELECT edu_coursesstudents.course_id, " +
					"edu_courses.name, " +
					"edu_courses.url, "+
					"edu_instructors.name as instructor_name," +
					"edu_institutions.name as institution_name, " +
					"AVG(IFNULL(edu_courserates.course_rate,0)) as course_rate "+
					"FROM edu_coursesstudents " +
					"LEFT Join edu_courses " +
						"on edu_coursesstudents.course_id=edu_courses.course_id " +
					"LEFT Join edu_instructors " +
						"on edu_courses.instructor_id = edu_instructors.id " +
					"LEFT Join edu_institutions " +
						"on  edu_courses.institution_id = edu_institutions.id " +
					"LEFT Join edu_users " +
						"on edu_coursesstudents.user_id=edu_users.user_id " +
					"LEFT Join edu_courserates " +
						"on edu_courserates.course_id=edu_users.user_id " +
					"Where edu_coursesstudents.course_id IN ("+sb.toString()+") "+
					"group by edu_coursesstudents.course_id," +
					"edu_courses.name," +
					"edu_courses.url," +
					"edu_instructors.name," +
					"edu_institutions.name";
		   	return Ebean.createSqlQuery(rs).findList().toArray();
	   	}
	   	return new Object[]{};
   }

   public static Result getRecommendedCoursesForUser(){
	   	return ok(Json.toJson(fetchRecommendedCoursesForUser(session().get("user_id"))));
   }
   
   public static Result getRecommendedCoursesOfUserForMobile(String deviceId){
	   int userId = MobileUtils.findUserIdFromDeviceId(deviceId);
	   return ok(Json.toJson(fetchRecommendedCoursesForUser(userId+"")));
   }
   
   public static Result addComment(String course_id, String comment){
	    java.util.Date now = new java.util.Date();	    
	   	Long longTime = new Long(now.getTime()/1000);
	   	
	   		   
	   
		edu_comments ec = new edu_comments();
		ec.user_id = Integer.parseInt(session().get("user_id"));
		ec.course_id = Integer.parseInt(course_id);
		ec.comment_date = longTime.intValue();;
		ec.reply_to_id = 0;
		ec.subject = "";
		ec.comment = comment;
		ec.save();
	   return ok("It Works!!");
   }
   
   public static Result agreeComment(String comment_id){
	   String sq="SELECT * FROM edu_commentvotes WHERE comment_id='"+comment_id+"' AND user_id='"+session().get("user_id")+"' AND vote=1";
       Object[] ccc= Ebean.createSqlQuery(sq).findList().toArray();
       if(ccc.length==0)
       {  
	   	edu_commentvotes ecv = new edu_commentvotes();
		ecv.user_id = Integer.parseInt(session().get("user_id"));
		ecv.comment_id = Integer.parseInt(comment_id);
		ecv.vote = 1;
		ecv.vote_date = "";
		ecv.save();		
       }	   	  
	   return ok("It Works!!");
  }
   
   public static Result disagreeComment(String comment_id){
	   
       String sq="SELECT * FROM edu_commentvotes WHERE comment_id='"+comment_id+"' AND user_id='"+session().get("user_id")+"' AND vote=0";       
       Object[] ccc= Ebean.createSqlQuery(sq).findList().toArray();                    
       if(ccc.length==0)
       {     
    	   	edu_commentvotes ecv = new edu_commentvotes();
   			ecv.user_id = Integer.parseInt(session().get("user_id"));
			ecv.comment_id = Integer.parseInt(comment_id);
			ecv.vote = 0;
			ecv.vote_date = "";
			ecv.save();    	   
       }
	   return ok("It Works!!");
 }   
   
}

